package com.gitee.wsl.mathematics.geometry.d2.line.ext

import com.gitee.wsl.mathematics.coordinate.d2.Point2
import com.gitee.wsl.mathematics.geometry.d2.line.LineShape2d
import com.gitee.wsl.mathematics.vector.ext.dot
import com.gitee.wsl.mathematics.vector.ext.clamp

fun<T:Number,V:Point2<T,V>> LineShape2d<T, V>.projectedPoint(p: Point2<T,*>) = projectedPointOutsideSegment(p).clamp(min, max)

fun<T:Number,V:Point2<T,V>> LineShape2d<T, V>.projectedPointOutsideSegment(p: Point2<T,*>): V {
    val v1x = x0
    val v2x = x1
    val v1y = y0
    val v2y = y1
    val px = p.x
    val py = p.y

    // return this.getIntersectionPoint(Line(point, Point.fromPolar(point, this.angle + 90.degrees)))!!
    // get dot product of e1, e2
    val e1x = v2x - v1x
    val e1y = v2y - v1y
    val e2x = px - v1x
    val e2y = py - v1y
    val valDp = createPoint2(e1x, e1y) dot createPoint2(e2x, e2y)
    // get length of vectors

    val lenLineE1 = hypot(e1x, e1y)
    val lenLineE2 = hypot(e2x, e2y)

    // What happens if lenLineE1 or lenLineE2 are zero?, it would be a division by zero.
    // Does that mean that the point is on the line, and we should use it?
    if (lenLineE1 == 0.0 || lenLineE2 == 0.0) {
        return createPoint2(px, py)
    }

    val cos = valDp / (lenLineE1 * lenLineE2)

    // length of v1P'
    val projLenOfLine = cos * lenLineE2

    return createPoint2((v1x + (projLenOfLine * e1x) / lenLineE1), (v1y + (projLenOfLine * e1y) / lenLineE1))
}